// PlayerAI.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.Linq;

using Supremacy.Collections;
using Supremacy.Diplomacy;
using Supremacy.Entities;
using Supremacy.Game;
using Supremacy.Orbitals;
using Supremacy.Universe;

namespace Supremacy.AI
{
    public static class PlayerAI
    {
        #region Constants
        private const int DangerRange = 4;
        private const int MaxDistanceInConvexHull = 3;
        #endregion

        #region Methods
        public static bool ConsiderOffer(Deal offer)
        {
            if (offer == null)
                return false;

            Civilization them = offer.Sender;
            Civilization us = offer.Recipient;

            IList<TradeData> theirList = offer.SenderItems;
            IList<TradeData> ourList = offer.RecipientItems;

            //int threshold = 0;

            if ((theirList.Count == 0) && (ourList.Count == 0))
                return true;

            if (DiplomacyHelper.IsCreditsDeal(theirList) && DiplomacyHelper.IsCreditsDeal(ourList))
                return false;

            foreach (TradeData item in ourList)
            {
                if (GetTradeDenial(us, them, item) != DenialType.NoDenial)
                    return false;
            }

            return true;
        }

        public static ConvexHullSet CreateDesiredBorders(Civilization civ)
        {
            if (civ == null)
                throw new ArgumentNullException("civ");

            var map = GameContext.Current.Universe.Map;
            var sectorClaims = GameContext.Current.SectorClaims;
            var disjointSets = new List<IEnumerable<MapLocation>>();
            var convexHulls = new List<ConvexHull>();

            for (int x = 0; x < map.Width; x++)
            {
                for (int y = 0; y < map.Height; y++)
                {
                    var location = new MapLocation(x, y);
                    if (!sectorClaims.IsClaimedByCiv(location, civ))
                        continue;
                    var disjointSet = new List<MapLocation>(1) { location };
                    disjointSets.Add(disjointSet);
                }
            }

            for (int i = 0; i < disjointSets.Count; i++)
            {
                for (int j = 0; j < disjointSets.Count; j++)
                {
                    bool merge = false;
                    if (i == j)
                        continue;
                    foreach (var location1 in disjointSets[i])
                    {
                        foreach (var location2 in disjointSets[j])
                        {
                            if (MapLocation.GetDistance(location1, location2) > MaxDistanceInConvexHull)
                                continue;
                            merge = true;
                            break;
                        }
                        if (merge)
                            break;
                    }
                    if (!merge)
                        continue;
                    disjointSets[i] = disjointSets[i].Union(disjointSets[j]);
                    disjointSets.RemoveAt(j);
                    if (i > j)
                        --i;
                    --j;
                }
            }

            foreach (var disjointSet in disjointSets)
                convexHulls.Add(new ConvexHull(disjointSet));

            return new ConvexHullSet(convexHulls);
        }

        public static int GetCreditTradeValuePercent(Civilization who)
        {
            if (who == null)
                throw new ArgumentNullException("who");
            int value = 1;
            if (IsInFinancialTrouble(who))
                value++;
            return (100 * value);
        }

        public static int GetFleetDanger(Fleet fleet, int range, bool testMoves, bool anyDanger)
        {
            return GetSectorDanger(fleet.Owner, fleet.Sector, range, testMoves);
        }

        public static int GetSectorDanger(Civilization who, Sector sector, int range, bool testMoves)
        {
            if (who == null)
                throw new ArgumentNullException("who");
            if (sector == null)
                throw new ArgumentNullException("sector");
            SectorMap map = GameContext.Current.Universe.Map;
            int count = 0;
            int borderDanger = 0;

            if (range < 0)
                range = DangerRange;

            for (int dX = -range; dX < range; dX++)
            {
                for (int dY = -range; dY < range; dY++)
                {
                    int distance;
                    Sector loopSector = map[sector.Location.X + dX, sector.Location.Y + dY];
                    if (loopSector == null)
                        continue;
                    distance = MapLocation.GetDistance(sector.Location, loopSector.Location);
                    if (AtWar(who, loopSector.Owner))
                    {
                        if (distance <= 2)
                            borderDanger++;
                    }
                    foreach (Fleet fleet in GameContext.Current.Universe.FindAt<Fleet>(loopSector.Location))
                    {
                        if (AtWar(who, fleet.Owner))
                        {
                            if (fleet.IsCombatant)
                            {
                                FleetView fleetView = FleetView.Create(who, fleet);
                                if (fleetView.IsPresenceKnown)
                                {
                                    if (UnitAI.CanEnterSector(sector, fleet.Owner))
                                    {
                                        if (!testMoves || (fleet.Speed >= distance))
                                        {
                                            count++;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (IsHuman(who))
            {
                count += borderDanger;
            }

            return count;
        }

        public static AIStrategies GetStrategies(Civilization who)
        {
            return AIStrategies.Default;
        }

        public static DenialType GetTradeDenial(Civilization who, Civilization whoTo, TradeData item)
        {
            if (who == null)
                throw new ArgumentNullException("who");
            if (whoTo == null)
                throw new ArgumentNullException("whoTo");
            if (item == null)
                throw new ArgumentNullException("item");

            Civilization target;
            Colony colony;

            switch (item.ItemType)
            {
                case TradableItem.Resource:
                    return ConsiderResourceTrade(who, whoTo, item);

                case TradableItem.Colony:
                    colony = GameContext.Current.Universe.Get<Colony>(item.Data1);
                    if (colony != null)
                    {
                        return ConsiderColonyTrade(who, whoTo, colony);
                    }
                    break;

                case TradableItem.Credits:
                case TradableItem.CreditsPerTurn:
                    break;

                case TradableItem.MapData:
                    return ConsiderMapDataTrade(who, whoTo);

                case TradableItem.Surrender:
                    return ConsiderSurrenderTrade(who, whoTo, 140);

                case TradableItem.Protectorate:
                    return ConsiderProtectorateTrade(who, whoTo);

                case TradableItem.MakePeace:
                    target = GameContext.Current.Civilizations[item.Data1];
                    return ConsiderMakePeaceTrade(who, whoTo, target);

                case TradableItem.DeclareWar:
                    target = GameContext.Current.Civilizations[item.Data1];
                    return ConsiderDeclareWarTrade(who, whoTo, target);

                case TradableItem.Embargo:
                    target = GameContext.Current.Civilizations[item.Data1];
                    return ConsiderEmbargoTrade(who, whoTo, target);

                case TradableItem.OpenBorders:
                    return ConsiderOpenBordersTrade(who);

                case TradableItem.DefensePact:
                    return ConsiderDefensePactTrade(who, whoTo);

                case TradableItem.PermanentAlliance:
                    return ConsiderPermanentAllianceTrade(who, whoTo);

                case TradableItem.Membership:
                    return ConsiderMembershipTrade(who, whoTo);

                case TradableItem.PeaceTreaty:
                    break;
            }

            return DenialType.NoDenial;
        }

        public static bool HasMetHuman(Civilization who)
        {
            if (who == null)
                throw new ArgumentNullException("who");
            foreach (Civilization otherCiv in GameContext.Current.Civilizations)
            {
                if (otherCiv != who)
                {
                    if (IsHuman(otherCiv) && DiplomacyHelper.IsContactMade(who, otherCiv))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public static bool IsHuman(Civilization who)
        {
            if (who == null)
                throw new ArgumentNullException("who");
            return PlayerContext.Current.IsHumanPlayer(who);
        }

        public static bool IsInFinancialTrouble(Civilization who)
        {
            if (who == null)
                throw new ArgumentNullException("who");
            try
            {
                CivilizationManager civManager = GameContext.Current.CivilizationManagers[who];
                if ((civManager != null) && (civManager.Credits.LastChange < 0))
                    return true;
            }
            catch {}
            return false;
        }

        private static bool AtWar(Civilization source, Civilization target)
        {
            if ((source == null) || (target == null) || (source == target))
                return false;
            return (GameContext.Current.Relationships[source, target].Status == RelationshipStatus.AtWar);
        }

        private static DenialType ConsiderColonyTrade(Civilization who, Civilization whoTo, Colony colony)
        {
            return DenialType.Never;
        }

        private static DenialType ConsiderDeclareWarTrade(Civilization who, Civilization toWho, Civilization target)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderDefensePactTrade(Civilization who, Civilization to)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderEmbargoTrade(Civilization who, Civilization whoTo, Civilization target)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderMakePeaceTrade(Civilization who, Civilization whoTo, Civilization target)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderMapDataTrade(Civilization who, Civilization whoTo)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderMembershipTrade(Civilization who, Civilization to)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderOpenBordersTrade(Civilization who)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderPermanentAllianceTrade(Civilization who, Civilization to)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderProtectorateTrade(Civilization who, Civilization whoTo)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderResourceTrade(Civilization who, Civilization whoTo, TradeData item)
        {
            throw new NotImplementedException();
        }

        private static DenialType ConsiderSurrenderTrade(Civilization who, Civilization whoTo, int i)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}